package com.yyg.usecase.concurrent;

import org.junit.Assert;
import org.junit.Test;
import org.slf4j.MDC;

import java.util.Map;
import java.util.concurrent.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @Author: 冰岩
 * @Date: 2024/03/27
 * @Description:
 */

public class CompletableFutureTest {

    static InheritableThreadLocal<Map<String, String>> inheritableThreadLocal = new InheritableThreadLocal();

    @Test
    public void supplyAsyncAndThenApplyTest() {

        ExecutorService executorService = new ThreadPoolExecutor(1, 10,
            1L, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1024),
                new ThreadPoolExecutor.AbortPolicy());

        Supplier<String> supplier = () -> {
            return "hello world";
        };

        Function<String, String> applier = s -> {
            return s + " #thenApply";
        };

        CompletableFuture<String> future = CompletableFuture.supplyAsync(supplier, executorService)
            .thenApply(applier);

        String s = future.join();
        Assert.assertEquals("hello world #thenApply", s);

    }

    @Test
    public void supplyAsyncAndHandleTest() {
        ExecutorService executorService = new ThreadPoolExecutor(1, 10,
            1L, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1024),
            new ThreadPoolExecutor.AbortPolicy());
        Supplier<String> supplier = () -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "hello world";
        };
        BiFunction<String, Throwable, String> handler = (s,e) -> {
            if (e != null) {
                e.printStackTrace();
            }
            return s + " append by handler";
        };
        CompletableFuture<String> future = CompletableFuture.supplyAsync(supplier, executorService)
            .handle(handler)
            .whenComplete((s, throwable) -> {
            if (throwable != null) {
                throwable.printStackTrace();
            } else {
                System.out.println("whenComplete exe success, result: " + s);
            }
        });
        String s = future.join();
        Assert.assertEquals("hello world append by handler", s);
    }


    @Test
    public void subThreadInheritedLocalMap_TraceIdNotMiss_Test() throws ExecutionException, InterruptedException {
        int traceId = 111;
        MDC.put("traceId", String.valueOf(traceId));
        inheritableThreadLocal.set(MDC.getCopyOfContextMap());
        ExecutorService executor = Executors.newFixedThreadPool(10);
        executor.execute(() -> {
            System.out.println("异步任务开始执行");
            System.out.println("异步任务执行结束");
            MDC.setContextMap(inheritableThreadLocal.get());
            System.out.println("subTreadTraceId:" + MDC.get("traceId"));
        });
        System.out.println("main traceId:" + MDC.get("traceId"));
    }

    @Test
    public void subThread_TraceIdMiss_Test() throws ExecutionException, InterruptedException {
        int traceId = 111;
        MDC.put("traceId", String.valueOf(traceId));
        ExecutorService executor = Executors.newFixedThreadPool(10);
        executor.execute(() -> {
            System.out.println("异步任务开始执行");
            System.out.println("异步任务执行结束");
            System.out.println("subTreadTraceId:" + MDC.get("traceId"));
        });
        System.out.println("main traceId:" + MDC.get("traceId"));
    }

    @Test
    public void subThread_TraceIdNotMiss_Test() throws ExecutionException, InterruptedException {
        int traceId = 111;
        MDC.put("traceId", String.valueOf(traceId));
        ExecutorService executor = Executors.newFixedThreadPool(10, new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                String traceId = MDC.get("traceId");
                return new Thread(()->{
                    MDC.put("traceId", traceId);
                    r.run();
                });
            }
        });
        executor.execute(() -> {

            System.out.println("异步任务开始执行");
            System.out.println("异步任务执行结束");
            System.out.println("subTreadTraceId:" + MDC.get("traceId"));
        });
    }

    @Test
    public void subThread_newThread_TraceIdNotMiss_Test() throws ExecutionException, InterruptedException {
        int traceId = 111;
        MDC.put("traceId", String.valueOf(traceId));
        Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap();
//        inheritableThreadLocal.set(MDC.getCopyOfContextMap());
        new Thread(()->{
//            MDC.setContextMap(inheritableThreadLocal.get());
            MDC.setContextMap(copyOfContextMap);
            System.out.println("subThread traceId:" + MDC.get("traceId"));
        }).start();
        System.out.println("main traceId:" + MDC.get("traceId"));
    }

    @Test
    public void subThread_excutors_newThread_TraceIdNotMiss_Test() throws ExecutionException, InterruptedException {
        int traceId = 111;
        MDC.put("traceId", String.valueOf(traceId));
        ExecutorService excutors = Executors.newFixedThreadPool(10, new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                String traceId = MDC.get("traceId");
                return new Thread(()->{
                    r.run();
                    MDC.put("traceId", traceId);
                    System.out.println("subThread traceId1:" + MDC.get("traceId"));
                });
            }
        });
        excutors.execute(()->{
            System.out.println("subThread traceId2:" + MDC.get("traceId"));
        });
        System.out.println("main traceId:" + MDC.get("traceId"));
        excutors.shutdown();
    }

    @Test
    public void subThread_CompletableFuture_newThread_TraceIdMiss_Test() throws ExecutionException, InterruptedException {
        MDC.put("traceId", String.valueOf(111));
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(()->{
            return MDC.get("traceId");
        });
        System.out.println("异步执行的返回结果：" + completableFuture.get());
        System.out.println("main traceId:" + MDC.get("traceId"));
    }
    @Test
    public void subThread_CompletableFuture_newThread_TraceIdNotMiss_Test() throws ExecutionException, InterruptedException {
        MDC.put("traceId", String.valueOf(111));
        String traceId = MDC.get("traceId");
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(()->{
            MDC.put("traceId", traceId);
            return MDC.get("traceId");
        });
        System.out.println("异步执行的返回结果get：" + completableFuture.get());
        System.out.println("异步执行的返回结果join：" + completableFuture.join());
        System.out.println("main traceId:" + MDC.get("traceId"));
    }

}
